﻿using System;
using System.Collections.Generic;
using System.Linq;
using MvcEngine.Mvc.StarterSite.Controllers;
using System.Web.Mvc;
using MvcEngine.Mvc.Models.ViewModels;
using MvcEngine.Blog.Models.Entities;
using MvcEngine.Blog.Components.Extensions;
using MvcEngine.Blog.Models.ViewData;
using MvcEngine.Core;
using MvcEngine.Mvc.Extensions;
using MvcEngine.Blog.Repositories;
using MvcEngine.Core.Repositories;
using MvcEngine.Core.Helpers;
using MvcEngine.Blog.Helper;
using System.Web;
using MvcEngine.Mvc.Filters;
using MvcEngine.Core.Exceptions;
using MvcEngine.Core.Configuration;
using MvcEngine.Blog.Components.Attributes;
using MvcEngine.Mvc;
using MvcEngine.Mvc.Models;
using System.IO;
using MvcEngine.Core.Extensions;
using MvcEngine.Blog.Managers;
using MvcEngine.Core.Content;
using MvcEngine.Blog.Models;
using MvcEngine.Mvc.Controllers;
using MvcEngine.Core.Pagination;
using MvcEngine.Blog.Filters;

namespace MvcEngine.Blog.StarterSite.Controllers
{
    public class BlogPostController : SubController
    {
        #region Private fields

        private IBlogPostRepository postRepository = null;
        private IBlogTagRepository tagRepository = null;
        private IBlogCategoryRepository categoryRepository = null;
        private IBlogPostCommentRepository commentRepository = null;
        private IBlogPostNotifyRepository notifyRepository = null;

        #endregion

        #region Constructors

        public BlogPostController()
        {
            postRepository = IoC.Resolve<IBlogPostRepository>();
            tagRepository = IoC.Resolve<IBlogTagRepository>();
            categoryRepository = IoC.Resolve<IBlogCategoryRepository>();
            commentRepository = IoC.Resolve<IBlogPostCommentRepository>();
            notifyRepository = IoC.Resolve<IBlogPostNotifyRepository>();
        }

        #endregion

        [BlogActionSetupAttribute]
        public MvcEngineModel Index(Guid blogId, int? pageNumber)
        {
            int postsPerPage = BlogManager.Current.GetBlog(blogId).PostsPerPage;
            if (!pageNumber.HasValue)
                pageNumber = 1;
            if (pageNumber.Value <= 0)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            IPagination<BlogPost> pagination = BlogPostManager.Current.GetPosts(blogId, pageNumber.Value, postsPerPage, true);
            if (pagination.TotalItems == 0)
                return new MvcEngineModel { ViewName = "Empty" };
            if (pageNumber.Value > pagination.TotalPages)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            BlogPostPaginationViewModel model = new BlogPostPaginationViewModel()
            {
                HasNextPage = pagination.HasNextPage,
                HasPreviousPage = pagination.HasPreviousPage,
                NextPage = pagination.NextPage,
                PreviousPage = pagination.PreviousPage,
                Posts = new List<BlogPostDetailsViewModel>()
            };

            foreach (var post in pagination)
            {
                var postViewModel = new BlogPostDetailsViewModel()
                {
                    Id = post.Id,
                    Slug = post.Slug,
                    BlogId = post.BlogId,
                    Author = post.Author,
                    Comments = BlogPostManager.Current.GetComments(post.Id),
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Title = post.Title,
                    UseShortVersion = true,
                    PublishedDate = post.PublishedDate,
                    PostContent = post.PostContent
                };
                model.Posts.Add(postViewModel);
            }

            return model;
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public MvcEngineModel CategoryFilter(Guid blogId, string categoryName, int? pageNumber)
        {
            int postsPerPage = BlogManager.Current.GetBlog(blogId).PostsPerPage;
            if (!pageNumber.HasValue)
                pageNumber = 1;
            if (pageNumber.Value <= 0)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            var category = categoryRepository.Get(blogId, categoryName);
            if (category == null)
                return new MvcEngineModel { ViewName = "CategoryNotFound" };

            IPagination<BlogPost> pagination = BlogPostManager.Current.GetPostsByCategory(category.Id, pageNumber.Value, postsPerPage);

            if (pagination.TotalItems == 0)
                return new MvcEngineModel { ViewName = "Empty" };
            if (pageNumber.Value > pagination.TotalPages)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };


            BlogPostPaginationViewModel model = new BlogPostPaginationViewModel()
            {
                HasNextPage = pagination.HasNextPage,
                HasPreviousPage = pagination.HasPreviousPage,
                NextPage = pagination.NextPage,
                PreviousPage = pagination.PreviousPage,
                Posts = new List<BlogPostDetailsViewModel>()
            };

            foreach (var post in pagination)
            {
                var postViewModel = new BlogPostDetailsViewModel()
                {
                    Id = post.Id,
                    Slug = post.Slug,
                    BlogId = post.BlogId,
                    Author = post.Author,
                    Comments = BlogPostManager.Current.GetComments(post.Id),
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Title = post.Title,
                    UseShortVersion = true,
                    PublishedDate = post.PublishedDate,
                    PostContent = post.PostContent,
                    ViewName = "CategoryFilter"
                };
                model.Posts.Add(postViewModel);
            }

            return model;
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public MvcEngineModel TagFilter(Guid blogId, string tagName, int? pageNumber)
        {
            int postsPerPage = BlogManager.Current.GetBlog(blogId).PostsPerPage;
            if (!pageNumber.HasValue)
                pageNumber = 1;
            if (pageNumber.Value <= 0)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            BlogTagBase tag = tagRepository.Get(blogId, tagName);
            if (tag == null)
                return new MvcEngineModel { ViewName = "TagNotFound" };

            IPagination<BlogPost> pagination = BlogPostManager.Current.GetPostsByTag(tag.Id, pageNumber.Value, postsPerPage);

            if (pagination.TotalItems == 0)
                return new MvcEngineModel { ViewName = "Empty" };
            if (pageNumber.Value > pagination.TotalPages)
                return new MvcEngineModel { ViewName = "InvalidPageRequest" };

            BlogPostPaginationViewModel model = new BlogPostPaginationViewModel()
            {
                HasNextPage = pagination.HasNextPage,
                HasPreviousPage = pagination.HasPreviousPage,
                NextPage = pagination.NextPage,
                PreviousPage = pagination.PreviousPage,
                Posts = new List<BlogPostDetailsViewModel>(),
                ViewName = "TagFilter"
            };

            foreach (var post in pagination)
            {
                var postViewModel = new BlogPostDetailsViewModel()
                {
                    Id = post.Id,
                    Slug = post.Slug,
                    BlogId = post.BlogId,
                    Author = post.Author,
                    Comments = BlogPostManager.Current.GetComments(post.Id),
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Title = post.Title,
                    UseShortVersion = true,
                    PublishedDate = post.PublishedDate,
                    PostContent = post.PostContent,
                    ViewName = "TagFilter"
                };
                model.Posts.Add(postViewModel);
            }

            return model;
        }

        [AcceptVerbs(HttpVerbs.Get)]
        [PostActionSetupAttribute]
        public MvcEngineModel Details(Guid blogId, string postName)
        {
            BlogPost post = BlogPostManager.Current.GetPost(postName, blogId);
            if (post == null || (!post.PublishedDate.HasValue && !UserContext.Current.User.IsAdmin()))
                return new MvcEngineModel() { ViewName = "PostNotFound" };

            BlogData blog = BlogManager.Current.GetBlog(post.BlogId);

            var result = new BlogPostDetailsViewModel()
            {
                Id = post.Id,
                Slug = post.Slug,
                BlogId = post.BlogId,
                Author = post.Author,
                Comments = BlogPostManager.Current.GetComments(post.Id),
                PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                Title = post.Title,
                PublishedDate = post.PublishedDate,
                PostContent = post.PostContent,
                UseShortVersion = false,
                ShowCaptcha = blog.ShowCaptcha,
                IsCommentEnabled = post.IsCommentEnabled && blog.AllowComments,
                ViewName = "Details"
            };

            if (!post.PublishedDate.HasValue && UserContext.Current.User.IsAdmin()) 
            {
                result.PublishedDate = DateTime.Now;
            }

            return result;
        }

        [AcceptVerbs(HttpVerbs.Get)]
        [PostActionSetupAttribute]
#warning try to rename this function to Details
        public MvcEngineModel PostDetails(Guid postId)
        {
            BlogPost post = BlogPostManager.Current.GetPost(postId);
            if (post == null)
                return new MvcEngineModel() { ViewName = "PostNotFound" };

            BlogData blog = BlogManager.Current.GetBlog(post.BlogId);

            return new BlogPostDetailsViewModel()
            {
                Id = post.Id,
                Slug = post.Slug,
                BlogId = post.BlogId,
                Author = post.Author,
                Comments = BlogPostManager.Current.GetComments(post.Id),
                PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                Title = post.Title,
                PublishedDate = post.PublishedDate,
                PostContent = post.PostContent,
                ViewName = "Details",
                UseShortVersion = false,
                ShowCaptcha = blog.ShowCaptcha,
                IsCommentEnabled = post.IsCommentEnabled && blog.AllowComments
            };
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public MvcEngineModel Rss(Guid blogId)
        {
            BlogData blog = BlogManager.Current.GetBlog(blogId);
            var posts = postRepository.GetPosts(blogId, blog.PostsInRss);

            PostRssViewModel model = new PostRssViewModel();
            model.BlogDescription = blog.BlogDescription;
            model.BlogTitle = blog.BlogName;
            model.Language = "ru-RU";
            model.ManagingEditor = "MvcEngine";
            model.WebMaster = blog.Email;
            model.Posts = new List<BlogPostDetailsViewModel>();

            foreach (var post in posts)
            {
                var postViewModel = new BlogPostDetailsViewModel()
                {
                    Id = post.Id,
                    Slug = post.Slug,
                    BlogId = post.BlogId,
                    Author = post.Author,
                    Comments = BlogPostManager.Current.GetComments(post.Id),
                    PostCategories = BlogCategoryManager.Current.GetAllByPost(post.Id),
                    PostTags = BlogPostTagManager.Current.GetAllByPost(post.Id),
                    Title = post.Title,
                    UseShortVersion = true,
                    PublishedDate = post.PublishedDate,
                    PostContent = post.PostContent,
                    ViewName = "TagFilter"
                };
                model.Posts.Add(postViewModel);
            }
            return model;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        [AntiForgeryValidationFilter]
        [BlogCaptchaFilter]
        public object CreateComment(Guid blogId, Guid postId, bool receiveUpdates, BlogPostComment comment)
        {
            BlogPost post = BlogPostManager.Current.GetPost(postId);
            BlogData blog = BlogManager.Current.GetBlog(blogId);

            bool isCommentsEnabled = post.IsCommentEnabled && blog.AllowComments;

            if (!isCommentsEnabled)
                return Redirect(Url.PostDetails(postId));

            if (ModelState.IsValid)
            {
                using (IUnitOfWork unitOfWork = UnitOfWorkHelper.Get())
                {
                    comment.Id = Guid.NewGuid();
                    comment.PostId = postId;
                    BlogPostManager.Current.SaveComment(comment);

                    foreach (var item in IoC.Resolve<IBlogPostNotifyRepository>().GetAll(post.Id))
                    {
                        BlogEmailHelper.Current.SendPostNotification(item.NotifyAddress,
                            comment.Author,
                            comment.Comment,
                            Url.AbsolutePath(Url.PostDetails(postId)),
                            post.Title);
                    }

                    if (receiveUpdates)
                    {
                        if (!notifyRepository.Exists(postId, comment.Email))
                        {
                            BlogPostNotify notify = IoC.Resolve<BlogPostNotify>();
                            notify.Id = Guid.NewGuid();
                            notify.NotifyAddress = comment.Email;
                            notify.PostId = post.Id;
                            notify.CreatedDate = DateTime.Now;
                            notify.ModifiedDate = DateTime.Now;
                            IoC.Resolve<IBlogPostNotifyRepository>().Add(notify);
                        }
                    }
                    BlogEmailHelper.Current.SendPostNotificationToAdmin(comment.Author, comment.Comment, Url.PostDetails(postId), post.Title);
                    unitOfWork.Commit();
                }
                return Redirect(Url.PostDetails(postId));
            }
            return Details(blogId, post.Slug);
        }
    }
}
